package com.nuo.quartz.serve.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuo.common.core.page.PageResult;
import com.nuo.common.quartz.core.entity.QuartzJobDO;
import com.nuo.common.quartz.core.entity.QuartzLogDO;
import com.nuo.common.quartz.core.enums.JobStateEnum;
import com.nuo.common.quartz.core.operate.QuartzOperate;
import com.nuo.common.web.exception.BizException;
import com.nuo.quartz.beans.pojo.request.QuartzJobAddReqDTO;
import com.nuo.quartz.beans.pojo.request.QuartzJobPageQueryReqDTO;
import com.nuo.quartz.beans.pojo.request.QuartzJobUpdateReqDTO;
import com.nuo.quartz.beans.pojo.request.QuartzLogPageQueryReqDTO;
import com.nuo.quartz.beans.pojo.response.QuartzJobRespDTO;
import com.nuo.quartz.beans.pojo.response.QuartzLogRespDTO;
import com.nuo.quartz.serve.mapper.QuartzJobDOMapper;
import com.nuo.quartz.serve.mapper.QuartzLogDOMapper;
import com.nuo.quartz.serve.service.QuartzJobDOService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @author LGC
 */
@Slf4j
@Service
public class QuartzJobDOServiceImpl extends ServiceImpl<QuartzJobDOMapper, QuartzJobDO> implements QuartzJobDOService {

    @Resource
    private QuartzJobDOMapper quartzJobMapper;

    @Resource
    private QuartzLogDOMapper quartzLogMapper;

    @Resource
    private QuartzOperate quartzOperate;

    /**
     * 初始化加载定时任务
     */
    @PostConstruct
    public void init() {
        LambdaQueryWrapper<QuartzJobDO> queryWrapper = new LambdaQueryWrapper<>();
        List<QuartzJobDO> jobList = quartzJobMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(jobList)) {
            jobList.forEach(quartzJobDO -> {
                if (quartzJobDO.getState().equals(JobStateEnum.JOB_RUN.getStatus())) {
                    quartzOperate.createJob(quartzJobDO);
                }
                if (quartzJobDO.getState().equals(JobStateEnum.JOB_STOP.getStatus())) {
                    quartzOperate.checkStop(quartzJobDO);
                }
                if (quartzJobDO.getState().equals(JobStateEnum.JOB_DEL.getStatus())) {
                    quartzOperate.deleteJob(quartzJobDO.getId());
                }
            });
        }
    }

    @Override
    public QuartzJobRespDTO getById(Integer id) {
        QuartzJobDO quartzJobDO = this.baseMapper.selectById(id);
        if (ObjectUtil.isNull(quartzJobDO) || quartzJobDO.getState().equals(JobStateEnum.JOB_DEL.getStatus())) {
            throw new BizException("任务不存在");
        }
        return BeanUtil.copyProperties(quartzJobDO, QuartzJobRespDTO.class);
    }

    @Override
    public PageResult<QuartzJobRespDTO> jobPage(QuartzJobPageQueryReqDTO dto) {
        Page<QuartzJobDO> page = new LambdaQueryChainWrapper<>(this.baseMapper)
                .eq(dto.getJobId() != null, QuartzJobDO::getId, dto.getJobId())
                .eq(StrUtil.isNotBlank(dto.getBeanName()), QuartzJobDO::getBeanName, dto.getBeanName())
                .page(dto.getPage().getPage());
        return new PageResult<>(page, QuartzJobRespDTO.class);
    }


    @Override
    public Integer add(QuartzJobAddReqDTO dto) {
        QuartzJobDO quartzJobDO = BeanUtil.copyProperties(dto, QuartzJobDO.class);
        if (ObjectUtil.isNotNull(quartzJobDO)) {
            quartzJobDO.setCreateTime(new Date());
            quartzJobDO.setUpdateTime(new Date());
            int flag = quartzJobMapper.insert(quartzJobDO);
            if (flag > 0) {
                quartzOperate.createJob(quartzJobDO);
            }
            return flag;
        }
        return 0;
    }


    @Override
    public Integer update(QuartzJobUpdateReqDTO dto) {
        QuartzJobDO quartzJobDO = this.baseMapper.selectById(dto.getId());
        if (ObjectUtil.isNull(quartzJobDO)) {
            throw new BizException("任务不存在");
        }
        QuartzJobDO updateQuartzJob = BeanUtil.copyProperties(dto, QuartzJobDO.class);
        updateQuartzJob.setUpdateTime(new Date());
        int flag = quartzJobMapper.updateById(updateQuartzJob);
        if (flag > 0) {
            quartzOperate.updateJob(updateQuartzJob);
        }
        return flag;
    }

    @Override
    public void pause(Integer id) {
        QuartzJobDO quartzJobDO = this.baseMapper.selectById(id);
        if (ObjectUtil.isNull(quartzJobDO)) {
            throw new BizException("任务不存在");
        }
        quartzJobDO.setState(JobStateEnum.JOB_STOP.getStatus());
        quartzJobDO.setUpdateTime(new Date());
        if (quartzJobMapper.updateById(quartzJobDO) > 0) {
            quartzOperate.checkStop(quartzJobDO);
        }
    }


    @Override
    public void resume(Integer id) {
        QuartzJobDO quartzJobDO = this.baseMapper.selectById(id);
        if (quartzJobDO != null) {
            quartzJobDO.setState(JobStateEnum.JOB_RUN.getStatus());
            quartzJobDO.setUpdateTime(new Date());
            if (quartzJobMapper.updateById(quartzJobDO) > 0) {
                quartzOperate.resumeJob(id);
            }
        }
    }

    @Override
    public void runOnce(Integer id) {
        QuartzJobDO quartzJobDO = this.baseMapper.selectById(id);
        if (ObjectUtil.isNull(quartzJobDO) || quartzJobDO.getState().equals(JobStateEnum.JOB_DEL.getStatus())) {
            throw new BizException("任务不存在");
        }
        quartzOperate.run(quartzJobDO);
    }


    @Override
    public PageResult<QuartzLogRespDTO> jobLogPage(QuartzLogPageQueryReqDTO dto) {
        Page<QuartzLogDO> page = new LambdaQueryChainWrapper<>(quartzLogMapper)
                .eq(dto.getJobId() != null, QuartzLogDO::getJobId, dto.getJobId())
                .eq(StrUtil.isNotBlank(dto.getBeanName()), QuartzLogDO::getBeanName, dto.getBeanName())
                .page(dto.getPage().getPage());
        return new PageResult<>(page, QuartzLogRespDTO.class);
    }
}
